<?php
/**
 * Each engineer has a duty to keep the code elegant
 * Created by wolffy.
 * Author @wolffy<13750088090@sina.cn>
 * Date: 2018/8/19
 * Time: 19:30
 */
namespace App\Services;

use App\Repositories\RepaymentBillRepository;
use App\Repositories\RepaymentPlanConsumeRepository;
use App\Repositories\RepaymentPlanRepaymentRepository;
use App\Repositories\RepaymentPlanRepository;
use App\Repositories\ThreeApiErrorLogsRepository;
use App\Repositories\UserCreditCardRepository;
use App\Repositories\UserPassageRepository;
use App\Repositories\UserRepository;
use App\Services\Area\AreaService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class RepaymentPlanService extends CommonService
{
    protected $userRepository;
    protected $userCreditCardRepository;
    protected $repaymentBillRepository;
    protected $repaymentPlanRepository;
    protected $repaymentPlanConsumeRepository;
    protected $repaymentPlanRepaymentRepository;
    protected $userPassageRepository;
    protected $userPassageService;
    protected $repaymentBillService;
    protected $cloudspSMS;
    protected $repaymentPlanJobsService;
    protected $messageService;
    protected $landingRepaymentCService;
    protected $landingRepaymentEService;
    protected $threeApiErrorLogsRepository;
    protected $areaService;
    protected $repaymentAddParams = [];
    protected $consumeAddParams = [];

    public function __construct(UserRepository $userRepository, UserCreditCardRepository $userCreditCardRepository,
                                RepaymentBillRepository $repaymentBillRepository, RepaymentPlanRepository $repaymentPlanRepository,
                                RepaymentPlanConsumeRepository $repaymentPlanConsumeRepository, RepaymentPlanRepaymentRepository $repaymentPlanRepaymentRepository,
                                UserPassageRepository $userPassageRepository, UserPassageService $userPassageService,
                                RepaymentBillService $repaymentBillService, CloudspSMS $cloudspSMS,
                                RepaymentPlanJobsService $repaymentPlanJobsService, MessageService $messageService,
                                ThreeApiErrorLogsRepository $threeApiErrorLogsRepository, AreaService $areaService)
    {
        $this->userRepository = $userRepository;
        $this->userCreditCardRepository = $userCreditCardRepository;
        $this->repaymentBillRepository = $repaymentBillRepository;
        $this->repaymentPlanRepository = $repaymentPlanRepository;
        $this->repaymentPlanConsumeRepository = $repaymentPlanConsumeRepository;
        $this->repaymentPlanRepaymentRepository = $repaymentPlanRepaymentRepository;
        $this->userPassageRepository = $userPassageRepository;
        $this->userPassageService = $userPassageService;
        $this->repaymentBillService = $repaymentBillService;
        $this->cloudspSMS = $cloudspSMS;
        $this->repaymentPlanJobsService = $repaymentPlanJobsService;
        $this->messageService = $messageService;
        $this->threeApiErrorLogsRepository = $threeApiErrorLogsRepository;
        $this->areaService = $areaService;
    }

    /**
     * 制定计划
     * @param $user
     * @param $creditId
     * @param $repaymentPlanJson
     * @return \Illuminate\Http\JsonResponse
     */
    public function makePlan($user, $creditId, $repaymentPlanJson, $expireDate, $cvn2, $address)
    {
        if (empty($expireDate) || empty($cvn2)) {
            return $this->responseJson(10517);//信用卡认证
        }
        //判断是否有绑定
        $creditCard = $this->userCreditCardRepository->validateCreditCardIsUser($creditId, $user['user_id']);
        if (empty($creditCard->bank_no) || 0 == $creditCard->is_bind) {
            return $this->responseJson(10306);//信用卡不存在
        }
        //一个月有上个和这个还款日，两个的处理
        $monthBillDate = getMonthBillDate($creditCard->bill_day, $creditCard->repayment_day);
        //获取本月账单
        $bill = $this->repaymentBillRepository->getRepaymentBill($user['user_id'], $creditId, $monthBillDate);
        if (empty($bill)) {
            return $this->responseJson(10400);//账单不存在
        }
        //是否有待执行和执行中的记录
        $isHasRunOrNoRun = $this->isHasRunOrNoRun($bill->id);
        if (is_object($isHasRunOrNoRun)) return $isHasRunOrNoRun;
        $repaymentPlanData = json_decode($repaymentPlanJson, true);
        $paramsDate = array_column($repaymentPlanData['bill'], 'repayment_every_time_date');
        $paramsDateUnique = array_values(array_unique($paramsDate));
        if (count($paramsDate) != count($paramsDateUnique)) {
            return $this->responseJson(422, [], false, '还款日期格式不正确', '还款日期格式不正确');
        }
        //根据通道获取子商户号
        $userPassageMerchantNo = $this->userPassageRepository->getSubMerchantNo($repaymentPlanData['passage_id'], $user['user_id']);
        //是否需要开卡
        if ($repaymentPlanData['passage_id'] == 1) {
            $isOpenCard = $this->userPassageService->isHasSubMerchantOpenCard($user, $creditId, $repaymentPlanData['passage_id'], $userPassageMerchantNo, $expireDate, $cvn2);
            if (is_object($isOpenCard)) return $isOpenCard;
        }
        $dates = $this->repaymentBillService->repaymentDateIsOk($paramsDateUnique, $bill->bill_date, $bill->repayment_date);//用户选择的还款日期
        if (is_object($dates)) return $dates;
        $this->consumeAddParams = [
            'realname' => $user['realname'],
            'idcard_number' => $user['idcard_number'],
            'bank_mobile' => $creditCard->bank_mobile,
            'expire_date' => $expireDate,
            'cvn2' => $cvn2
        ];
        $this->repaymentAddParams = [
            'bank_mobile' => $creditCard->bank_mobile,
        ];
        $planSn = makeOrderNo();
        //开启事务
        DB::beginTransaction();
        try {
            $planData = [
                'plan_sn' => $planSn,
                'repayment_bill_id' => $bill->id,
                'passage_id' => $repaymentPlanData['passage_id'],
                'repayment_money' => $repaymentPlanData['repayment_money'],
                'repayment_days' => $repaymentPlanData['repayment_days'],
                'repayment_service_charge' => $repaymentPlanData['service_charge'],
                'lowest_card_money' => $repaymentPlanData['lowest_card_money'],
                'repayment_plan_status' => 1000,
                'create_plan_time' => time(),
                'user_id' => $user['user_id'],
                'finish_plan_time' => $repaymentPlanData['finish_plan_time'],
            ];
            $repaymentPlanId = $this->repaymentPlanRepository->insertGetId($planData);
            if (0 < $repaymentPlanId) {
                foreach ($repaymentPlanData['bill'] as $key=>$value) {
                    $planRepaymentData = [
                        'plan_repayment_sn' => makeOrderNo(),
                        'repayment_plan_id' => $repaymentPlanId,
                        'repayment_passage_id' => $value['repayment_passage_id'],
                        'repayment_every_time_date' => $value['repayment_every_time_date'],
                        'repayment_every_time' => strtotime($value['repayment_every_time_date'] . '' . $value['repayment_every_time']),
                        'repayment_every_time_money' => $value['repayment_every_time_money'],
                        'repayment_every_status' => 3000,
                        'create_plan_repayment_time' => time(),
                        'sub_merchant_no' => $userPassageMerchantNo,
                        'bank_no' => $creditCard->bank_no,
                    ];
                    $planRepaymentId = $this->repaymentPlanRepaymentRepository->insertGetId($planRepaymentData);
                    foreach ($value['detail'] as $kk=>$item) {
                        $consumeData = [
                            'plan_consume_sn' => makeOrderNo(),
                            'repayment_plan_id' => $repaymentPlanId,
                            'plan_repayment_id' => $planRepaymentId,
                            'consume_passage_id' => $item['consume_passage_id'],
                            'consume_money' => $item['consume_money'],
                            'consume_date' => $value['repayment_every_time_date'],
                            'consume_time' => strtotime($value['repayment_every_time_date'] . '' . $item['consume_time']),
                            'consume_type_mcc' => $item['consume_type_mcc'],
                            'consume_type_name' => $item['consume_type_name'],
                            'consume_address' => serialize(json_decode($address)),
                            'consume_service_charge' => $item['consume_service_charge'],
                            'consume_rate' => $item['consume_rate'],
                            'consume_every_time_price' => $item['consume_every_time_price'],
                            'repayment_consume_status' => 2000,
                            'create_plan_consume_time' => time(),
                            'sub_merchant_no' => $userPassageMerchantNo,
                            'bank_no' => $creditCard->bank_no
                        ];
                        if (!empty($consumeCard) && $key == 0) {
                            $consumeData['bank_no'] = $consumeCard->bank_no;
                        }
                        $this->repaymentPlanConsumeRepository->create($consumeData);
                    }
                }
                DB::commit();
                $this->intoRedisJobs($bill->id);
                //计划提醒
                $this->messageService->messageTemplate(15, $user['invited_code'], $creditCard->bank_no, $creditCard->bank_description,
                    $repaymentPlanData['repayment_money'], '', '',
                    $repaymentPlanId, $repaymentPlanData['lowest_card_money'], '', '');
                //您的尾号{1}订单{2}已生效。回T退订
                $content = substr($creditCard->bank_no, -4) . '##' . $planSn;
                $this->cloudspSMS->sendSMSNotify($user['mobile'], $content, 'createOrder', 6);
                return $this->responseJson(0, [
                    'plan_id' => $repaymentPlanId
                ]);
            } else {
                DB::rollBack();
                return $this->responseJson(400);
            }
        } catch (\Exception $e) {
            DB::rollBack();
            return $this->responseJson(400, [], false, $e->getMessage(), '');
        }
    }

    /**
     * 进消费任务与还款任务
     * @param $billId
     */
    public function intoRedisJobs($billId)
    {
        //根据账单ID获取计划ID
        $getPlan = $this->repaymentPlanRepository->ByBillId($billId)->toArray();
        Log::info('intoRedisJobs' . json_encode($getPlan));
        $getPlanRepayment = $this->repaymentPlanRepaymentRepository->planRepaymentAll($getPlan['id'])->toArray();
        foreach ($getPlanRepayment as $value) {
            $planRepaymentRedisKey = $this->repaymentPlanRepayment() . $value['repayment_every_time_date'] . ':' . $value['repayment_every_time_date'];
            if ($value['repayment_passage_id'] == 3) {
                $value = array_merge($value, $this->repaymentAddParams);
            }
            //每天还款任务数据按时间排序
            $repaymentPlanRepaymentData = $this->redis()->lRange($planRepaymentRedisKey, 0, 1);
            if (!empty($repaymentPlanRepaymentData)) {
                $repaymentPlanRepaymentData = json_decode($repaymentPlanRepaymentData[0], true);
                if ($value['repayment_every_time'] >= $repaymentPlanRepaymentData['repayment_every_time']) {
                    $this->redis()->rPush($planRepaymentRedisKey, json_encode($value));//尾追加
                } else {
                    $this->redis()->lPush($planRepaymentRedisKey, json_encode($value));//头追加
                }
            } else {
                $this->redis()->rPush($planRepaymentRedisKey, json_encode($value));//尾追加
            }
            $this->redis()->expire($planRepaymentRedisKey, 86400 * 31);
            Log::info('planRepaymentRedis' . json_encode($value));
            $getPlanConsume = $this->repaymentPlanConsumeRepository->planRepaymentConsumeAll($value['id'])->toArray();
            foreach ($getPlanConsume as $val) {
                $planConsumeRedisKey = $this->repaymentPlanConsume() . $val['consume_date'] . ':' . $val['consume_date'];
                if ($val['consume_passage_id'] == 3) {
                    $val = array_merge($val, $this->consumeAddParams);
                }
                //每天消费任务数据按时间排序
                $repaymentPlanConsumeData = $this->redis()->lRange($planConsumeRedisKey, 0, 1);
                if (!empty($repaymentPlanConsumeData)) {
                    $repaymentPlanConsumeData = json_decode($repaymentPlanConsumeData[0], true);
                    if ($val['consume_time'] >= $repaymentPlanConsumeData['consume_time']) {
                        $this->redis()->rPush($planConsumeRedisKey, json_encode($val));//尾追加
                    } else {
                        $this->redis()->lPush($planConsumeRedisKey, json_encode($val));//头追加
                    }
                } else {
                    $this->redis()->rPush($planConsumeRedisKey, json_encode($val));//尾追加
                }
                $this->redis()->expire($planConsumeRedisKey, 86400 * 31);
                Log::info('planConsumeRedis' . json_encode($val));
            }
        }
    }

    /**
     * 还款计划详情
     * @param $planId
     */
    public function repaymentPlanDetail($planId, $userId)
    {
        $getPlan = $this->repaymentPlanRepository->getOnePlan($planId, $userId);
        if (empty($getPlan)) {
            return $this->responseJson(10512);//还款计划不存在
        }
        $getPlan = $getPlan->toArray();
        $bill = $this->repaymentBillRepository->byId($getPlan['repayment_bill_id']);
        $getPlan['credit_card_id'] = $bill->credit_card_id;
        $data = [];
        $getPlanRepayment = $this->repaymentPlanRepaymentRepository->planRepaymentAll($planId);
        if (!empty($getPlanRepayment)) {
            $getPlanRepayment = $getPlanRepayment->toArray();
            $getPlanRepayment = unsetColumn($getPlanRepayment, ['sub_merchant_no', 'bank_no']);
            foreach ($getPlanRepayment as $key=>$value) {
                $data[$key] = $value;
                $getPlanConsume = $this->repaymentPlanConsumeRepository->planRepaymentConsumeAll($value['id'])->toArray();
                $getPlanConsume = unsetColumn($getPlanConsume, ['sub_merchant_no', 'bank_no']);
                $data[$key]['consume'] = $getPlanConsume;
            }
            $getPlan['detail'] = $data;
        }
        return $this->responseJson(0, $getPlan);
    }

    /**
     * 终止计划
     * @param $planId
     * @return \Illuminate\Http\JsonResponse
     */
    public function updatePlanStatusToStop($planId, $userId)
    {
        $getPlan = $this->repaymentPlanRepository->getOnePlan($planId, $userId);
        if (empty($getPlan)) {
            return $this->responseJson(10512);//还款计划不存在
        }
        $bill = $this->repaymentBillRepository->byId($getPlan->repayment_bill_id);
        if (empty($bill)) {
            return $this->responseJson(10400);//账单不存在
        }
        $isBind = $this->userCreditCardRepository->validateCreditCardIsUser($bill->credit_card_id, $userId);
        if (empty($isBind->bank_no) || 0 == $isBind->is_bind) {
            return $this->responseJson(10306);//信用卡不存在
        }
        $plan = $this->repaymentPlanRepository->byId($planId);
        if (in_array($plan->repayment_plan_status, [1000, 1001, 1005])) {
            $isConsume = $this->repaymentPlanConsumeRepository->byStatus($planId, 2001);
            if (!empty($isConsume)) {
                return $this->responseJson(10522);//您当前有一笔处于消费或还款中，稍后再重试
            }
            $repayment = $this->repaymentPlanRepaymentRepository->planRepaymentToStatus($planId);
            $planRepaymentId = $repayment->id;
            $this->repaymentPlanJobsService->intoRepaymentAutoWithdrawJobs($plan->passage_id, $userId, $planId, $planRepaymentId);
            $plan->update([
                'repayment_plan_status' => 1004 //还款计划状态：1000待执行 1001执行中 1002成功 1003失败 1004停止计划 1005继续执行
            ]);
        } else {
            return $this->responseJson(10523);//非取消计划状态
        }
        $repaymentPlan = $this->repaymentPlanRepository->byId($planId);
        return $this->responseJson(0, ['repayment_plan_status' => $repaymentPlan->repayment_plan_status]);
    }

    /**
     * 继续执行计划
     * @param $planId
     * @return \Illuminate\Http\JsonResponse
     */
    public function updatePlanStatusToContinue($planId, $user, $expireDate, $cvn2)
    {
        $getPlan = $this->repaymentPlanRepository->getOnePlan($planId, $user['user_id']);
        if (empty($getPlan)) {
            return $this->responseJson(10512);//还款计划不存在
        }
        $bill = $this->repaymentBillRepository->byId($getPlan->repayment_bill_id);
        if (empty($bill)) {
            return $this->responseJson(10400);//账单不存在
        }
        $isBind = $this->userCreditCardRepository->validateCreditCardIsUser($bill->credit_card_id, $user['user_id']);
        if (empty($isBind->bank_no) || 0 == $isBind->is_bind) {
            return $this->responseJson(10306);//信用卡不存在
        }
        $repaymentPlan = $this->repaymentPlanRepository->byId($planId);
        if ($repaymentPlan->passage_id == 3) {
            if (empty($expireDate) || empty($cvn2)) {
                return $this->responseJson(10517);//信用卡认证
            }
        }
        $getPlanRepayment = $this->repaymentPlanRepaymentRepository->planRepaymentToDate($planId, date('Y-m-d'));
        $getPlanConsume = $this->repaymentPlanConsumeRepository->repaymentPlanConsumeAllToDate($planId, date('Y-m-d'));
        if ($repaymentPlan->repayment_plan_status == 1005) {
            //消费失败处理
            $planConsumeFail = [];
            $consumeNextKey = 0;
            foreach ($getPlanConsume as $key=>$value) {
                if ($value['repayment_consume_status'] == 2003) {
                    $planConsumeFail = $value;
                    $consumeNextKey = $key + 1;
                    break;
                }
            }
            if (!empty($planConsumeFail)) {
                //判断是否在下一笔消费前30分钟，最后一笔消费拿还款前30分钟
                if ($consumeNextKey <= count($getPlanConsume) - 1) {
                    $canTime = $getPlanConsume[$consumeNextKey]['consume_time'];
                } else {
                    $canTime = $getPlanRepayment->repayment_every_time;
                }
                if (time() < $canTime - 1800) {
                    $planConsumeFail = $planConsumeFail->toArray();
                    $planConsumeFail['plan_consume_sn'] = makeOrderNo();
                    $this->repaymentPlanConsumeRepository->updateSnById($planConsumeFail['id'], $planConsumeFail['plan_consume_sn']);
                    if ($planConsumeFail['consume_passage_id'] == 1) {
                        $this->repaymentPlanJobsService->consumeSmallAmount($repaymentPlan, $planConsumeFail);
                    }
                    if ($planConsumeFail['consume_passage_id'] == 3) {
                        $consumeAddParams = [
                            'realname' => $user['realname'],
                            'idcard_number' => $user['idcard_number'],
                            'bank_mobile' => $isBind->bank_mobile,
                            'expire_date' => $expireDate,
                            'cvn2' => $cvn2
                        ];
                        $this->repaymentPlanJobsService->consumeLargeAmount($repaymentPlan,
                            array_merge($planConsumeFail, $consumeAddParams));
                    }
                }
            }
        } else {
            return $this->responseJson(10518);//非继续执行状态
        }
        $repaymentPlan->update(['repayment_plan_status' => 1001, 'update_plan_time' => time()]);
        return $this->responseJson(0, ['repayment_plan_status' => 1001]);
    }

    public function isHasRunOrNoRun($billId)
    {
        $isHasRunOrNoRun = $this->repaymentPlanRepository->isHasRunOrNoRun($billId);
        if (!empty($isHasRunOrNoRun->toArray())) {
            $planId = $isHasRunOrNoRun->toArray()[0]['id'];
            return $this->responseJson(10511, ['plan_id' => $planId]);//还款计划在执行中，额外添加，需手动终止
        }
        return true;
    }

    /**
     * 删除还款计划
     * @param $planId
     * @param $userId
     * @return \Illuminate\Http\JsonResponse
     */
    public function delete($planId, $userId)
    {
        $plan = $this->repaymentPlanRepository->getOnePlan($planId, $userId);
        if (empty($plan)) {
            return $this->responseJson(10512);//还款计划不存在
        }
        if ($plan->repayment_plan_status != 1004) {
            return $this->responseJson(10523);//非取消计划状态
        }
        $plan->update(['is_delete' => 1, 'update_plan_time' => time()]);
        return $this->responseJson(0);
    }

}
